<!--
 * @Author: your name
 * @Date: 2021-01-18 09:41:14
 * @LastEditTime: 2022-01-20 14:26:41
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \vue3-element-admin\src\components\Common.vue
-->
<template>
    <div class="ve_404">
        <!-- partial:index.partial.html -->
        <div class="star star1">⭐</div>
        <div class="star star2">⭐</div>
        <div class="star star3">⭐</div>
        <div class="star star4">⭐</div>
        <div class="star star5">⭐</div>
        <slot>
            <div class="error">
                <div class="error__title">404</div>
                <div class="error__subtitle">🐱🐱🐱(⓿_⓿)🐱🐱🐱</div>
                <div class="error__description">看来你是迷路了......</div>
                <router-link to="/">
                    <button class="error__button error__button--active">
                        回到首页
                    </button>
                </router-link>
                <!-- <button class="error__button">CONTACT</button> -->
            </div>
        </slot>
        <div class="astronaut" v-resize="{ resize: draw3dAstronaut }">
            <canvas ref="cav"></canvas>
        </div>
    </div>
</template>

<script setup>
import Zdog from "zdog";
import { ref, onUnmounted, onMounted } from "vue";
const cav = ref(null);
let timer = null;
onMounted(() => {
    draw3dAstronaut();
});
/**
 * @description: 画3d粉色食人魔
 * @param {*}
 * @return {*}
 */
const draw3dAstronaut = () => {
    cav.value.width = cav.value.parentNode.clientWidth;
    cav.value.height = cav.value.parentNode.clientHeight;

    let isSpinning = true;
    let TAU = Zdog.TAU;

    // colours
    let pink = "#f8B";
    let blush = "#F5A";
    let black = "#333";
    let shoe = "#D03";
    let red = "#E10";
    let yellow = "#FD0";

    // create illo
    let illo = new Zdog.Illustration({
        // set canvas with selector
        element: cav.value,
        dragRotate: true,
        zoom: 8,
    });

    /** Body **/
    // Body
    let body = new Zdog.Shape({
        stroke: 22,
        translate: { y: 11 },
        rotate: { x: 0.3, z: 0.1 },
        addTo: illo,
        color: pink,
    });

    // face
    let face = new Zdog.Anchor({
        translate: { z: 10.5 },
        addTo: body,
    });

    [-1, 1].forEach(function (xSide) {
        let eyeGroup = new Zdog.Group({
            addTo: face,
            translate: { x: 2.4 * xSide, y: -2 },
            rotate: { x: -0.1 },
        });
        // eye
        new Zdog.Ellipse({
            width: 1.4,
            height: 5.5,
            addTo: eyeGroup,
            stroke: 1,
            color: black,
            fill: true,
        });
        // eye highlight
        new Zdog.Ellipse({
            width: 1,
            height: 2,
            addTo: eyeGroup,
            translate: { y: -1.5, z: 0.5 },
            stroke: 0.5,
            color: "#FFF",
            fill: true,
        });

        // cheek holder
        let cheekHolder = new Zdog.Anchor({
            addTo: body,
            rotate: { y: 0.6 * xSide },
        });

        new Zdog.Ellipse({
            width: 2.5,
            height: 1,
            translate: { y: 1, z: 10.5 },
            addTo: cheekHolder,
            color: blush,
            stroke: 1,
        });
    });

    // mouth
    new Zdog.Shape({
        path: [
            { x: 0, y: 0 },
            {
                bezier: [
                    { x: 1.1, y: 0 },
                    { x: 1.1, y: 0.2 },
                    { x: 1.1, y: 0.5 },
                ],
            },
            {
                bezier: [
                    { x: 1.1, y: 1.1 },
                    { x: 0.2, y: 1.8 },
                    { x: 0, y: 1.8 },
                ],
            },
            {
                bezier: [
                    { x: -0.2, y: 1.8 },
                    { x: -1.1, y: 1.1 },
                    { x: -1.1, y: 0.5 },
                ],
            },
            {
                bezier: [
                    { x: -1.1, y: 0.2 },
                    { x: -1.1, y: 0 },
                    { x: 0, y: 0 },
                ],
            },
        ],
        addTo: face,
        translate: { y: 2, z: -0.5 },
        stroke: 1,
        color: shoe,
        fill: true,
    });

    let rightArm = new Zdog.Shape({
        path: [{ y: 0 }, { y: -7 }],
        addTo: body,
        translate: { x: -6, y: -4, z: 0 },
        color: pink,
        stroke: 7,
    });

    // left arm
    rightArm.copy({
        path: [{ x: 0 }, { x: 6 }],
        translate: { x: 6, y: -2, z: 0 },
    });

    // right foot
    let rightFoot = new Zdog.Shape({
        path: [
            { x: 0, y: -2 },
            {
                arc: [
                    { x: 2, y: -2 },
                    { x: 2, y: 0 },
                ],
            },
            {
                arc: [
                    { x: 2, y: 5 },
                    { x: 0, y: 5 },
                ],
            },
            {
                arc: [
                    { x: -2, y: 5 },
                    { x: -2, y: 0 },
                ],
            },
            {
                arc: [
                    { x: -2, y: -2 },
                    { x: 0, y: -2 },
                ],
            },
        ],
        addTo: body,
        translate: { x: -1, y: 9, z: -9 },
        rotate: { z: 0.2 },
        stroke: 6,
        color: shoe,
        fill: true,
        closed: false,
    });

    rightFoot.copy({
        translate: { x: 9.5, y: 6, z: -6 },
        rotate: { z: -1.1, y: 0.8 },
    });

    // ----- umbrella ----- //

    // umbrella rod
    let umbrella = new Zdog.Shape({
        path: [{ y: 0 }, { y: 22 }],
        addTo: rightArm,
        translate: { y: -33, z: 2 },
        rotate: { y: 0.5 },
        color: yellow,
        stroke: 1,
    });

    // star
    let starPath = (() => {
        let path = [];
        let starRadiusA = 3;
        let starRadiusB = 1.7;
        for (let i = 0; i < 10; i++) {
            let radius = i % 2 ? starRadiusA : starRadiusB;
            let angle = (TAU * i) / 10 + TAU / 4;
            let point = {
                x: Math.cos(angle) * radius,
                y: Math.sin(angle) * radius,
            };
            path.push(point);
        }
        return path;
    })();
    // star shape
    let star = new Zdog.Shape({
        path: starPath,
        addTo: umbrella,
        translate: { y: -4.5 },
        stroke: 2,
        color: yellow,
        fill: true,
    });

    // umbrella handle
    new Zdog.Shape({
        path: [
            { z: 0, y: 0 },
            { z: 0, y: 1 },
            {
                arc: [
                    { z: 0, y: 4 },
                    { z: 3, y: 4 },
                ],
            },
            {
                arc: [
                    { z: 6, y: 4 },
                    { z: 6, y: 1 },
                ],
            },
        ],
        addTo: umbrella,
        translate: { y: 23 },
        stroke: 2,
        color: "#37F",
        closed: false,
    });

    // umbrella shield panels
    (function () {
        let umbPanelX = 14 * Math.sin(TAU / 24);
        let umbPanelZ = 14 * Math.cos(TAU / 24);
        for (let i = 0; i < 12; i++) {
            let colorSide = Math.floor(i / 2) % 2;
            new Zdog.Shape({
                path: [
                    { x: 0, y: 0, z: 0 },
                    {
                        arc: [
                            { x: -umbPanelX, y: 0, z: umbPanelZ },
                            { x: -umbPanelX, y: 14, z: umbPanelZ },
                        ],
                    },
                    { x: umbPanelX, y: 14, z: umbPanelZ },
                    {
                        arc: [
                            { x: umbPanelX, y: 0, z: umbPanelZ },
                            { x: 0, y: 0, z: 0 },
                        ],
                    },
                ],
                addTo: umbrella,
                rotate: { y: (TAU / 12) * i },
                stroke: 1,
                color: colorSide ? red : "white",
                fill: true,
            });
        }
    })();

    // floater stars
    (function () {
        for (let i = 0; i < 6; i++) {
            let starHolder = new Zdog.Anchor({
                addTo: umbrella,
                translate: { y: 10 },
                rotate: { y: (TAU / 6) * i + TAU / 24 },
            });
            star.copy({
                addTo: starHolder,
                translate: { z: 28 },
            });
        }
    })();

    // ----- animate ----- //

    function animate() {
        illo.rotate.y += isSpinning ? -0.03 : 0;
        illo.updateRenderGraph();
        requestAnimationFrame(animate);
    }

    animate();
};
onUnmounted(() => {
    cancelAnimationFrame(timer);
    timer = null;
});
</script>

<style lang="scss" scoped>
.ve_404 {
    height: 100vh;
    width: 100vw;
    position: relative;
    overflow: hidden;
    background-image: url("../assets/kirby-bg.png");
    background-repeat: no-repeat;
    background-size: 100% 100%;
}

.star {
    color: grey;
    position: absolute;
    width: 10px;
    height: 10px;
    content: "";
    border-radius: 100%;
    transform: rotate(250deg);
    opacity: 0.4;
    animation-name: shimmer;
    animation-duration: 1.5s;
    animation-iteration-count: infinite;
    animation-direction: alternate;
}

@keyframes shimmer {
    from {
        opacity: 0;
    }

    to {
        opacity: 0.7;
    }
}

.star1 {
    top: 40%;
    left: 50%;
    animation-delay: 1s;
}

.star2 {
    top: 60%;
    left: 90%;
    animation-delay: 3s;
}

.star3 {
    top: 10%;
    left: 70%;
    animation-delay: 2s;
}

.star4 {
    top: 90%;
    left: 40%;
}

.star5 {
    top: 20%;
    left: 30%;
    animation-delay: 0.5s;
}

.astronaut {
    position: absolute;
    width: 60vw;
    height: 100vh;
    top: 0;
    right: 0;
    z-index: 0;
}

.error {
    position: absolute;
    left: 100px;
    top: 400px;
    transform: translateY(-60%);
    font-family: "Righteous", cursive;
    color: #363e49;
    z-index: 1;
}

.error__title {
    font-size: 10em;
    font-weight: bold;
    color: #d0d0d0;
    text-shadow: -5px -5px 0 rgba(0, 0, 0, 0.7);
    background-image: linear-gradient(90deg, #d0d0d0 48%, #919191 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

.error__subtitle {
    font-size: 2em;
}

.error__description {
    opacity: 0.5;
}

.error__button {
    min-width: 7em;
    margin-top: 3em;
    margin-right: 0.5em;
    padding: 0.5em 2em;
    outline: none;
    border: 2px solid #2f3640;
    background-color: transparent;
    border-radius: 8em;
    color: #576375;
    cursor: pointer;
    transition-duration: 0.2s;
    font-size: 0.75em;
    font-family: "Righteous", cursive;
}

.error__button:hover {
    color: #21252c;
}

.error__button--active {
    background-color: $base-color;
    border: 2px solid $base-color;
    color: white;
}

.error__button--active:hover {
    box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.5);
    color: white;
}
</style>
